Skip to content

This Dot Blog

This Dot provides teams with technical leaders who bring deep knowledge of the web platform. We help teams set new standards, and deliver results predictably.

Newest First
Tags:Stripe Apps
How to Login in to Third Party Services in Stripe Apps with OAuth PKCE cover image

How to Login in to Third Party Services in Stripe Apps with OAuth PKCE

One of the benefits of Stripe Apps is that they allow you to connect to third-party services directly from the Stripe Dashboard. There are many ways to implement the OAuth flows to authenticate with a third-party service, but the ideal one for Stripe Apps is PKCE. Unlike other OAuth flows, a Stripe app authenticating with a third-party using PKCE does not require any kind of backend. The entire process can take place in the user's browser. What is OAuth PKCE Proof Code for Key Exchange (PKCE, pronounced "pixie") is an extension of regular OAuth flows. It is designed for when you've got a client where it would be possible to access a secret key, such as a native app, or a single-page app. Because Stripe Apps are very restricted for security purposes, the OAuth PKCE flow is the only OAuth flow that works in Stripe Apps without requiring a separate backend. Not all third-party services support the PKCE authorization flow. One that does is Dropbox, and we will use that for our code examples. Using createOAuthState and oauthContext to Get an Auth Token To use the OAuth PKCE flow, you'll use createOAuthState from the Stripe UI Extension SDK to generate a state and code challenge. We will use these to request a code and verifier from Dropbox. Dropbox will then respond to a specific endpoint for our Stripe App with the code and verifier, which we'll have access to in the oauthContext. With these, we can finally get our access token. If you wish to follow along, you'll need to both create a Stripe App and a Dropbox App. We'll start by creating state to save our oauthState and challenge, and then get a code and verifier if we don't have one already. If we do have a code and verifier, we'll try to get the token, and put it in tokenData state. ` ` ` Fetch Dropbox User Data To prove to ourselves that the token works, let's fetch Dropbox user data using the token. We'll create a new function to fetch this user data, and call it from within our Stripe App's view. We'll store this user data in state. ` ` ` Storing Tokens with the Secret Store Currently, we're only persisting the retrieved token data in memory. As soon as we close the Stripe App, it will be forgotten and the user would have to fetch it all over again. For security reasons, we can't save it as a cookie or to local storage. But Stripe has a solution: the secret store. The secret store allows us to persist key-value data with Stripe itself. We can use this to save our token data and load it whenever a user opens our Stripe App. To make it easier to work with the secret store, we'll create a custom hook: useSecretStore. ` Once we've got our custom hook ready, we can integrate it into our App.tsx view. We will rewrite the useEffect to check for a saved token in the secret store, and use that if it's valid. Only if there is no token available do we create a new one, which will then be persisted to the secret store. We also add a Log Out button, which will reset the tokenData and secret store values to null. The Log Out button creates an issue. If we have oauthContext from logging in, and then we log out, the Stripe App still has the same oauthContext. If we tried logging in again without closing the app, we would get an error because we're re-using old credentials. To fix this, we also add a React ref to keep track of whether or not we've used our current oauthContext values. ` We've done a lot to create our authorization flow using PKCE. To see this entire example all together, check out this code sample on GitHub....

Creating Complex UIs Using the Stripe UI Extension SDK cover image

Creating Complex UIs Using the Stripe UI Extension SDK

Anyone who embarks on a journey to develop apps for the Stripe dashboard will need to grasp the concepts of frontend development using the Stripe UI Extension SDK. While a backend for your Stripe app may not always be necessary, a frontend is most certainly needed. In this blog, I will provide you with some tips & tricks that you might want to consider if you plan to develop more complex UIs. The Basics Stripe's UI Extension SDK is React-based. This means that you will need to have some React experience if you want to create Stripe apps. While Stripe apps are web apps, you will never touch HTML or CSS directly. In fact, you're forbidden to. This experience feels almost like developing in React Native. You use the provided UI primitives or components to scaffold your UI. When you open your app on the Stripe dashboard, you will see one of your app's *views*. Depending on where you are in the dashboard, you can open a view that is customer-related, payment-related, etc. Or, in the default case, you will open the default view if you are on the main dashboard page. A typical drawer view will have a ContextView component as its first child, and any other components from the UI toolkit as necessary. The main building block for your components is a Box. It's a plain block-level container, so you can think of it as a div. The Box, just like most other components, has a css property where you can apply styling. As mentioned before, you can't use real CSS though. Instead, you'll need to rely on the predefined CSS properties, most of which are very similar to real CSS properties in both naming and functionality. Just like we have a block-level container, we also have inline containers similar to span. In Stripe's case, this component is called Inline. All other components provide some additional functionality. Some of them are meant to be containers as well, while others are usually standalone. Navigating Within Views When you navigate through the Stripe dashboard, the dashboard will be opening different views in your app. On the Customers page, it will open a view for customers, for example (if such view is defined in stripe-app.json). However, what if you are on a view, but wish to navigate somewhere else within the view? Or maybe have functionality where you need to go back and forth between components? A typical scenario is having a widget, which, when clicked, opens more details, but within the same dashboard view. For this scenario, you can utilize React Router, specifically its MemoryRouter. Install it first: ` Since we don't have access to the DOM, and we cannot manipulate the browser location either, using MemoryRouter is good enough for our needs. It will store the current location as well as history in an internal memory array. You use it just like you would use the regular router. Let's assume that you need to authenticate your user before using the app. Let's also assume that, once logged in, you are shown an FAQ component with multiple questions. Once you click a FAQ question, you are directed to a FAQ answer within the view, as shown below: To model such transitions, you would use the React Router. The default view could have the following implementation: ` There are several things of note here. The ContextView is the root component in our DefaultView component. When we don't want to provide title and description of the ContextView, we use a space. You can't use an empty string, or leave out title and description all together. The first child of the ContextView is a Router. This is where our components will render, depending on our route. Remember that we use a MemoryRouter, and the route is an internal property of the router. It's not reflected in the window's location. When you open the view for the first time, you are presented with the AuthInit component. This component could check if you are authenticated, and if so, redirect you to /, and consequently the React Router will render the Faq component. Within the Faq component, we can use the useNavigate hook to navigate to a FaqEntry component to show the expanded question, and answer for a FAQ entry. For example: ` You can even try to extract the Router part into its own component, e.g. NavigationWrapper, and re-use it across views. In that case, you might consider including view IDs in the route to distinguish between different views. Following our example, this means our routes would become: ` The current view ID is always available in the environment?.viewportID property, should you ever need it. Using UserContext and Environment Everywhere The UserContext and Environment are so useful and so commonly used that it makes sense to store them in React context. Otherwise, you'd need to pass them down from your view component all the way to the components that need them. This is a technique known as "prop drilling" in the React world. First, define your context object: ` Now, simply wrap your view component in a context provider, and initialize it with the userContext and environment that are passed to your view: ` Now, you can use the useContext hook to retrieve properties from userContext and environment anywhere in your component tree. For example, this is how we would retrieve the payment object if we were on the payments page: ` Updating Title and Description Dynamically title and description are properties on the view level, but more often than not, you might want to update them dynamically as they are very context-dependant. In one of the above examples, we might want to display the FAQ answer in the title as we navigate to individual FAQ entries. In such cases, we can use React context again. Let's extend our GlobalContext with title and description properties, as well as setters for them. ` The DefaultView component now becomes: ` Now, any child component can update title and/or description, using the following snippet: ` Layout Options Before starting to model different type of layouts, it is highly recommended to learn the concept of "stacks". Stacks are Stripe's way of modelling flexbox-like layouts. It's not exactly the same as flexbox, but once you get the hang of it, you will find it to be very similar. You can stack up elements horizontally (on the "x" axis) or vertically (on the "y" axis). Furthermore, elements can be distributed in a different way along the axis, or aligned in a certain way, giving you the ability to make any kind of layout you can imagine. You can even stack up elements on top of each other. Whenever you want to align your content in any way, you need to use a stack. Key-Value Two-Column Layout Let's assume that you want to show key-value pairs in a two-column layout. This can be accomplished easily using stacks: ` The above code is for one row in the two-column layout. To add more, just add more blocks like these (or better, extract the above component in its own component). This is how it would be displayed in the app: The above code snippet has several things of note: - Whenever you use a width on a Box, make sure its parent has a gap defined. The reason is the way how the width is calculated - it takes gap into calculation, and if the gap is 0, the calculation will produce invalid width (which will just fit the content). - To align content of a Box (we used alignX: 'end'), the Box should be a stack. - In addition to using margin, you can also use marginTop, marginBottom, marginLeft, and marginRight to specify margin only on one (or more sides). - Vertically Aligning Elements Stacks are not only helpful for horizontal alignments. You can align vertically too, and this can come in handy if you want to nicely align an icon with a text label, or if you want to have form elements displayed in a straight line. For example: ` Wizards Whenever you need to have confirmation modals, or wizard-like flows, it's best to use the FocusView component. A focus view slides from the right and allows the user to have a dedicated space to perform a specific task, such as entering details to create a new entry in a database, or going through a wizard. A wizard can be implemented using two or more FocusView components. Here is an example of having a wizard with two components: ` Conclusion Stripe really did fantastic work to provide an amazing UI Extensions for developing custom Stripe apps. We hope this blog post provided you with some guidance on how to set solid foundations if you want to make more complex UIs using the Stripe UI Extension SDK. Stripe is continuously upgrading the UI Extension SDK, and you can definitely expect some new widgets to play with in the future!...

Integrating In-house Data and Workflows with Stripe Using Private Stripe Apps cover image

Integrating In-house Data and Workflows with Stripe Using Private Stripe Apps

Stripe Apps is a recently-announced platform that allows developers to embed content within Stripe's web UI, extending its functionality to allow interaction with non-Stripe services. Your immediate thought upon hearing of such a platform might be that it is useful for public services, such as customer support, to develop Stripe integrations. This is a core use-case and high-profile public integrations like those for Intercom and DocuSign have featured prominently in demonstrations of the platform's capabilities. However, you shouldn't overlook the value of private apps, developed specifically for your organization and visible only to your employees. Private apps may prove to be even more valuable, because they can specifically address your business' problems, automating domain-specific workflows, and integrate with in-house data and services. What is a private Stripe App? Stripe Apps published to the marketplace act like apps you might be familiar with from iOS or Android. They are developed for use by the public, each version of them goes through a strict review by Stripe, and they are published to the Stripe Marketplace where anyone can install them. Private Stripe Apps, in contrast, are published directly to the Stripe account that owns them. Since they are not going to be visible to users outside of the organization they are developed for, they don't have to go through the app review process, simplifying the development and maintenance process. Accessing internal services Since Stripe Apps are browser apps which execute on a user's own machine — as opposed to on Stripe's servers — private Stripe Apps can make use of resources that are only accessible from company-controlled devices. Intranet services and any internal authentication are accessible from your private Stripe App just as they are from any other browser-based internal tooling. There are only two caveats to accessing HTTP services from Stripe Apps. Both of them are driven by the security model of apps. The first is that services must be served over HTTPS, which is standard for internet-facing services, but might not be the case for private services on an intranet. The second one is that services must allow all cross-origin requests, since requests from Stripe Apps are made with a null origin, and therefore CORS allowlisting cannot be used to secure services against cross-site request forgery. If this is a major concern, endpoints specific to your Stripe App can be constructed that are secured through Stripe's request signing mechanism, and which proxy requests to the internal services only for requests signed with the App's secret. Enriching views with context-based data and workflows Stripe Apps are displayed on the same screen as Stripe objects like customers or invoices, and can access information about those objects and interact with them. This enables smoother workflows by operators by showing important context all in the same view. For example: - Displaying product shipping and returns information on the Invoice Details screen in order to make processing refunds more efficient. - Allowing operators to see — and maybe edit — the features that a given subscription plan includes directly in the Product Details screen. - Displaying account activity from multiple sources like access and change logs in the Customer Details screen in order to make it easier to resolve support queries. If anyone in your organization is currently working with multiple open browser tabs to manually collate information or execute workflows that cross service boundaries, a private Stripe App could help automate that process. This will free them up to do more valuable tasks, and reduce the likelihood of errors by making contextual information more reliably available, and eliminating manual steps....